/*
 * Copyright (c) 2021. Moses All Right Reserved
 */

package com.moses.design_patterns.factory_method;

import com.moses.design_patterns.factory_method.a.SimpleFactory;
import com.moses.design_patterns.factory_method.b.MutiMethodFacotry;
import com.moses.design_patterns.factory_method.c.StaticFacotry;
import com.moses.design_patterns.factory_method.d.AbstractFactory;
import com.moses.design_patterns.factory_method.d.ProductAFactory;
import com.moses.design_patterns.factory_method.d.ProductBFactory;
import com.moses.design_patterns.factory_method.e.AllInAbstractFactory;
import com.moses.design_patterns.factory_method.e.AllInFactoryImpl;
import com.moses.design_patterns.factory_method.f.SimpleAbstractFactory;
import com.moses.design_patterns.factory_method.f.SimpleAbstractFactoryImpl;

/**
 * @author Moses
 * @email shenhuohui@gmail.com
 * @date 2021/4/9 21:56
 */
public class Client {
    public static void main(String[] args){
        // 简单工厂使用
        SimpleFactory simpleFactory = new SimpleFactory();
        IProduct productA = simpleFactory.getProduct(ProductA.class);
        productA.product();

        IProduct productB = simpleFactory.getProduct(ProductB.class);
        productB.product();

        // 多工厂方法使用
        MutiMethodFacotry mutiMethodFacotry = new MutiMethodFacotry();
        ProductA productA1 = mutiMethodFacotry.getProductA();
        productA1.product();

        ProductB productB1 = mutiMethodFacotry.getProductB();
        productB1.product();

        // 静态工厂方法使用，方便直接调用，不用实例化工厂类
        // 可以将工厂类进行泛化，适合不同目标类型的实例
        // 推荐使用
        IProduct productA2 = StaticFacotry.getProduct(ProductA.class);
        productA2.product();
        IProduct productB2 = StaticFacotry.getProduct(ProductB.class);
        productB2.product();

        // 以上的Factory都是类，还可以抽象类
        // 分别由不同子类实现如何实例化
        // 每新增一个产品类，都得定义一个工厂对应
        // 目标类太多时，工厂类也多，代码写起来繁多
        AbstractFactory factory1 = new ProductAFactory();
        IProduct product1 = factory1.getProduct();
        product1.product();

        AbstractFactory factory2 = new ProductBFactory();
        IProduct product2 = factory2.getProduct();
        product2.product();

        // 也可以把不同实例化方法放一个抽象类里，由一个实现类实现，代码简洁，但是不符合开闭原则
        AllInAbstractFactory factory = new AllInFactoryImpl();
        ProductA productA3 = factory.getProductA();
        ProductB productB3 = factory.getProductB();
        productA3.product();
        productB3.product();

        // 如果一部分的目标类实例过程都一样，可以集中到一个类的一个方法中，
        // 对于实例过程不一样的可以专门拓展一个实现类来处理，以此类推
        // 既可以做到代码简洁，又可以做到符合开闭原则
        // 还可对这个抽象工厂类进行泛化，用于不同目标类型的实例，更符合设计
        // 推荐使用
        SimpleAbstractFactory factory3 = new SimpleAbstractFactoryImpl();
        ProductA productA4 = (ProductA) factory3.getProduct(ProductA.class);
        ProductB productB4 = (ProductB) factory3.getProduct(ProductB.class);
        productA4.product();
        productB4.product();

        // 另外，工厂方法模式也可以创建单例
    }
}
